# coding=utf-8
'''
Created on Jun 16, 2009

@license: License: LGPL
@copyright: (c) 2009, dogsing.cn
@author: ant-man
'''

from copy import deepcopy
from mocConstant import mocInt, mocTrue, mocFalse
from mocInstance import new_instance
from mocObject import MocObject, MocRuntimeException

class MocCollectionException(MocRuntimeException):pass

class MocIndexError(MocCollectionException):pass

class MocKeyError(MocCollectionException):pass


class MocCollection(MocObject):
    '''
    Base class of collection object in MOC
    '''

    TYPE = 'COLLECTION'

    def get_item(self, inst, idx):
        raise NotImplementedError()

    def add_item(self, inst, item):
        raise NotImplementedError()

    def get_len(self, inst):
        return mocInt(len(inst.value))

    def as_bool(self, inst):
        return len(inst.value) > 0

class MocList(MocCollection):
    """
    Represent list object in MOC
    """
    TYPE = "LIST"

    class MocListItem(object):

        def __init__(self, value=[]):
            """
            TODO:
            """
            self.value = list(value)
            self.iter_count = 0

        def __str__(self):
            return str(self.value)

        def __len__(self):
            return len(self.vaule)

    def new_inst(self, value):
        """
        TODO:
        """
        if isinstance(value, self.MocListItem) :
            return new_instance(self, value)
        return new_instance(self, self.MocListItem(value))

    def add_item(self, inst, item):
        # if item is a MocTempInstance, then it's value can not
        # be saved, so we need the refer of this instance
        inst.value.value.append(item.refer())

    def get_item(self, inst, idx):
        idx = idx.as_int()
        l = len(inst.value.value)
        # like python Moc support negative index
        if idx < 0 : idx = l + idx
        #  out-of range checking 
        if idx < 0 or idx >= l :
            raise MocIndexError("Index out of bound!")
        return inst.value.value[idx]

    def has_next(self, inst):
        l = len(inst.value.value)
        iter_count = inst.value.iter_count
        if l > iter_count :
            return mocTrue
        else :
            inst.value.iter_count = 0
            return mocFalse

    def next(self, inst):
        iter_count = inst.value.iter_count
        inst.value.iter_count += 1
        return inst.value.value[iter_count]

    def begin_itr(self, inst):
        """
        TODO:
        """
        inst.value.iter_count = 0

    def slice(self, inst, low, high):
        low = low.as_int()
        high = high.as_int()
        l = len(inst.value.value)
        ret = self.MocListItem(inst.value.value[low:high])
        return self.new_inst(ret)

    def pyval(self, inst):
        """
        """
        ls = []
        for val in inst.value.value :
            ls.append(val.pyval())
        return ls


class MocDict(MocCollection):
    """
    Represent dictionary object in MOC
    """
    TYPE = "DICT"

    def new_inst(self, value={}):
        new_inst = new_instance(self, dict(value))
        for key, val in value.items() :
            if isinstance(key, str) :
                new_inst.add_field(key, val)
        return new_inst

    def add_item(self, inst, key, value):
        inst.value[key.pyval()] = value.refer()
        if inst.type_equals("STRING"):
            # each key-value pair in dictionary instance
            # be seen as a field of this instance
            inst.add_field(key.pyval(), value)

    def get_item(self, inst, idx):
        dic = inst.value
        idx = idx.pyval()
        ret = dic.get(idx, None)
        if not ret :
            # try to find if in its instance field
            ret = inst.get_field(idx)
            if ret :
                return ret
        else :
            return  ret
        raise MocKeyError("Key error %s" % idx)

    def pyval(self, inst):
        """
        """
        dic = {}
        for val in inst.value.iterkeys() :
            dic[val] = inst.value[val].pyval()
        return dic


mocList = MocList()
mocDict = MocDict()

